#include "Wt.h"

int WtSessionCmd(ClientData clientData, Tcl_Interp *interp,
                 int objc, Tcl_Obj *const objv[])
{
  return WtSessionCmdHelper(clientData, interp, &w->session, objc, objv);
}

int WtSessionCmdHelper(ClientData clientData, Tcl_Interp *interp,
                       WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR;
  char *subCmd;

  if (objc < 2) {
    WtSessionUsage(interp, objv[0]);
    return ret;
  }

  subCmd = Tcl_GetString(objv[1]);

  if (!strcmp(subCmd, "count")) {
    ret = WtSessionCountCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "exists")) {
    ret = WtSessionExistsCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "get")) {
    ret = WtSessionGetCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "set")) {
    ret = WtSessionSetCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "add")) {
    ret = WtSessionAddCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "setDefault")) {
    ret = WtSessionSetDefaultCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "keys")) {
    ret = WtSessionKeysCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "values")) {
    ret = WtSessionValuesCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "remove")) {
    ret = WtSessionRemoveCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "removeList")) {
    ret = WtSessionRemoveListCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "array")) {
    ret = WtSessionArrayCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "table")) {
    ret = WtSessionTableCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "copy")) {
    ret = WtSessionCopyCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "clear")) {
    ret = WtSessionClearCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "getAll")) {
    ret = WtSessionGetAllCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "setAll")) {
    ret = WtSessionSetAllCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "addList")) {
    ret = WtSessionAddListCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "setAllDefault")) {
    ret = WtSessionSetAllDefaultCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "allValues")) {
    ret = WtSessionAllValuesCmd(clientData, interp, session, objc, objv);
  } else if (!strcmp(subCmd, "listArray")) {
    ret = WtSessionListArrayCmd(clientData, interp, session, objc, objv);
  } else {
    WtSessionUsage(interp, objv[0]);
  }

  return ret;
}

/* Session command usage */

WtSessionCmdUsage(Tcl_Interp *interp, Tcl_Obj *cmd)
{
  char *cmdStr = Tcl_GetString(cmd);

  Tcl_AppendResult(interp,
    cmdStr, " count\n",
    cmdStr, " exists key\n",
    cmdStr, " get key ?defaultValue?\n",
    cmdStr, " set key value\n",
    cmdStr, " add key value\n",
    cmdStr, " setDefault key value\n",
    cmdStr, " keys\n",
    cmdStr, " values\n",
    cmdStr, " remove key\n",
    cmdStr, " removeList keys\n",
    cmdStr, " array arrayName\n",
    cmdStr, " table\n",
    cmdStr, " copy\n",
    cmdStr, " clear\n",
    cmdStr, " getAll key ?defaultValue?\n",
    cmdStr, " setAll key list\n",
    cmdStr, " addList key list\n",
    cmdStr, " setAllDefault key list\n",
    cmdStr, " allValues\n",
    cmdStr, " listArray arrayName\n",
    NULL);
  }
}

/* count command */

int WtSessionCountCmd(ClientData clientData, Tcl_Interp *interp,
                  WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR, count;
  Tcl_Obj *obj;

  if (objc != 2) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
    return ret;
  } else {
    if (WtFetchSession(interp, session)) {
      count = WtTableSize(session->items);
      Tcl_SetObjResult(interp, Tcl_NewIntObj(count));
      ret = TCL_OK;
    }
  }

  return ret;
}

/* exists command */

int WtSessionExistsCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 3) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key", NULL);
    return ret;
  } else {
    if (WtFetchSession(interp, session)) {
      Tcl_SetObjResult(interp, Tcl_NewBooleanObj(
        WtTableExists(session->items, objv[2])));
      ret = TCL_OK;
    }
  }

  return ret;
}

/* get command */

int WtSessionGetCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,
  Tcl_Obj *obj;

  if (objc != 3 && objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key ?defaultValue?", NULL);
    return ret;
  } else {
    if (WtFetchSession(interp, session)) {
      obj = WtTableGet(session->items, objv[2]);
      if (obj) {
        Tcl_SetObjResult(interp, obj);
        ret = TCL_OK;
      } else if (obc > 3) {
        Tcl_SetObjResult(interp, objv[3]);
        ret = TCL_OK;
      } else {
        Tcl_AppendResult("No entry with key \"", Tcl_GetString(objv[2]),
          "\" exists, and no default value was specified.", NULL);
      }
    }
  }

  return ret;
}

/* set command */

int WtSessionSetCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key value", NULL);
    return ret;
  } else {
    WtTableSet(session->items, objv[2]);
    Tcl_SetObjResult(interp, objv[2]);
    ret = TCL_OK;
  }

  return ret;
}

/* add command */

int WtSessionAddCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key value", NULL);
    return ret;
  } else {
    WtTableAdd(session->items, objv[2]);
    Tcl_SetObjResult(interp, objv[2]);
    ret = TCL_OK;
  }

  return ret;
}

/* setDefault command */

int WtSessionSetDefaultCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key value", NULL);
    return ret;
  } else {
    if (WtFetchSession(interp, session)) {
      obj = WtTableGet(session->items, objv[2]);
      if (obj) {
        Tcl_SetObjResult(interp, obj);
      } else {
        WtTableSet(session->items, objv[2], objv[3]);
        Tcl_SetObjResult(interp, objv[3]);
      }
      ret = TCL_OK;
    }
  }

  return ret;
}

/* keys command */

int WtSessionKeysCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    if (WtFetchSession(interp, session)) {
      Tcl_SetObjResult(interp, WtTableKeys(session->items));
      ret = TCL_OK;
    }
  }

  return ret;
}

/* values command */

int WtSessionValuesCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    if (WtFetchSession(interp, session)) {
      Tcl_SetObjResult(interp, WtTableValues(session->items));
      ret = TCL_OK;
    }
  }

  return ret;
}

/* remove command */

int WtSessionRemoveCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 3) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " key", NULL);
  } else {
    WtTableRemove(session->items, objv[2]);
    ret = TCL_OK;
  }

  return ret;
}

/* removeList command */

int WtSessionRemoveListCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 3) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " list", NULL);
  } else {
    if (Tcl_ListObjLength(interp, objv[2], &listLen) != TCL_OK) {
      Tcl_AppendResult(interp,
        "Argument is not a list. Usage: ",
        WtToString(objv[0]), " ", WtToString(objv[1]), " list", NULL);
    } else {
      WtTableRemoveList(session->items, objv[2]);
      ret = TCL_OK;
    }
  }

  return ret;
}

/* array command */

int WtSessionArrayCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 3) {
    Tcl_AppendStringsToObj(interpRes, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), " arrayName",
      NULL);
  } else {
    if (WtFetchSession(interp, session)) {
      if (WtTableToArray(interp, session->items, objv[2], 0)) {
        ret = TCL_OK;
      }
    }
  }

  return ret;
}

/* table command */

int WtSessionTableCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendStringsToObj(interpRes, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    Tcl_SetObjResult(interp, Tcl_DuplicateObj(session->items));
    ret = TCL_OK;
  }

  return ret;
}

/* clear command */

int WtSessionClearCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendStringsToObj(interpRes, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    WtClearTable(session->items);
    ret = TCL_OK;
  }

  return ret;
}

/* getAll command */

int WtSessionGetAllCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc < 3 || objc > 4) {
    Tcl_AppendStringsToObj(interpRes, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " key ?defaultValue?", NULL);
  } else {
    if (WtFetchSession(interp, session)) {
      list = WtTableGetAll(session->items, objv[2]);
      if (list) {
        Tcl_SetObjResult(interp, list);
        ret = TCL_OK;
      } else if (objc > 3) {
        Tcl_SetObjResult(interp, objv[3]);
        ret = TCL_OK;
      } else {
        Tcl_AppendResult(interp, "No entry with key \"",
          WtToString(objv[2]), "\" exists, and no default value was specified.",
          NULL);
      }
    }
  }

  return ret;
}

/* setAll command */

int WtSessionSetAllCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendStringsToObj(interpRes, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " key list", NULL);
  } else {
    if (WtFetchSession(interp, session)) {
      if (Tcl_ListObjLength(interp, objv[3], &listLen) != TCL_OK) {
        Tcl_AppendResult(interp, "Value is not a list. Usage: ",
          WtToString(objv[0]), " ", WtToString(objv[1]),
          " key list", NULL);
      } else {
        WtTableSetAll(session->items, objv[2], objv[3]);
        Tcl_SetObjResult(interp, objv[3]);
        ret = TCL_OK;
      }
    }
  }

  return ret;
}

/* addList command */

int WtSessionAddListCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " key list", NULL);
  } else {
    if (Tcl_ListObjLength(interp, objv[3], &listLen) != TCL_OK) {
      Tcl_AppendResult(interp, "Value is not a list. Usage: ",
        WtToString(objv[0]), " ", WtToString(objv[1]),
        " key list", NULL);
    } else {
      WtTableAddList(session->items, objv[2], objv[3]);
      Tcl_SetObjResult(interp, objv[3]);
      ret = TCL_OK;
    }
  }

  return ret;
}

/* setAllDefault command */

int WtSessionSetAllDefaultCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 4) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " key list", NULL);
  } else {
    if (Tcl_ListObjLength(interp, objv[3], &listLen) != TCL_OK) {
      Tcl_AppendResult(interp, "Value is not a list. Usage: ",
        WtToString(objv[0]), " ", WtToString(objv[1]),
        " key list", NULL);
    } else {
      list = WtTableGetAll(tbl, objv[2]);
      if (list) {
        Tcl_SetObjResult(interp, list);
      } else {
        WtTableSetAll(tbl, objv[2], objv[3]);
        Tcl_SetObjResult(interp, objv[3]);
      }
      ret = TCL_OK;
    }
  }

  return ret;
}

/* allValues command */

int WtSessionAllValuesCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    Tcl_SetObjResult(interp, WtTableValues(session->items));
    ret = TCL_OK;
  }

  return ret;
}

/* listArray command */

int WtSessionListArrayCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 3) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " arrayName", NULL);
  } else {
    if (WtTableToArray(interp, session->items, objv[2], 1)) {
      ret = TCL_OK;
    }
  }

  return ret;
}

/* id command */

int WtSessionIdCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR, len;
  const char *bytes;

  w = (WtContext *)Tcl_GetAssocData(interp, "wt::context", NULL);

  if (objc != 2 && objc != 3) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]),
      " ?id?", NULL);
  } else {
    if (objc == 2) {
      Tcl_SetObjResult(interp, session->id);
    } else if (objc == 3) {
      if (WtSetSessionId(session, interp)) {

  }
      bytes = Tcl_GetStringFromObj(objv[2], &len);
      if (strcmp(bytes, Tcl_GetString(session->id))) {
        if (WtCommitSession(session, interp)) {
          WtSetSessionCookie(
          Tcl_SetStringObj(session->id, bytes, len);
          ret = TCL_OK;
        }
      } else {
        ret = TCL_OK;
      }
      if (ret == TCL_OK) {
        Tcl_SetObjResult(interp, session->id);
      }
    }
  }

  return ret;
}

void WtSetSessionId(session, Tcl_Obj *newId, Tcl_Interp *interp)
{
  int ok = 0, len;
  char *bytes;

  bytes = Tcl_GetStringFromObj(newId, &len);

  if (strcmp(bytes, Tcl_GetString(session->id))) {
    if (WtCommitSession(session, interp)) {
      cookie = WtNewCookieObj();

      WtAppendClnItem(w->active->response.cookies


      WtSetSessionCookie(
      Tcl_SetStringObj(session->id, bytes, len);
      ret = TCL_OK;
    }
      } else {
        ret = TCL_OK;
      }
      if (ret == TCL_OK) {
        Tcl_SetObjResult(interp, session->id);
      }
  return ok;
}

/* commit command */

int WtSessionCommitCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_ERROR,

  if (objc != 2) {
    Tcl_AppendResult(interp, "Incorrect usage. Should be: ",
      WtToString(objv[0]), " ", WtToString(objv[1]), NULL);
  } else {
    ret = WtSessionDriver(interp, session, "commit", objc, objv, 2);
  }

  return ret;
}

/* modified command */

int WtSessionModifiedCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_OK,

  if (session->removals->numEntries || session->additions->numEntries) {
    Tcl_SetResult(interp, Tcl_NewBooleanObj(1));
  } else {
    Tcl_SetResult(interp, Tcl_NewBooleanObj(0));
  }

  return ret;
}

/* destroy command */

int WtSessionDestroyCmd(ClientData clientData, Tcl_Interp *interp,
    WtSession *session, int objc, Tcl_Obj *const objv[])
{
  int ret = TCL_OK;
  WtContext *w;

  w = (WtContext *)Tcl_GetAssocData(interp, "wt::context", NULL);

  WtDestroySession(w, session);

  return ret;
}

int WtGetSessionId(Tcl_Interp *interp, WtContext *w, WtSession *session)
{
  if (sessionzz
}

/* Create session commands */

void WtInitSessionCommands(Tcl_Interp *interp)
{
  Tcl_CreateObjCommand(interp, "::wt::session::session", WtSessionCmd, NULL, NULL);
  Tcl_CreateObjCommand(interp, "::wt::session::cache", WtSessionCacheCmd, NULL, NULL);
}
